package net.sf.brutil.v0.server;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;

import net.sf.brutil.v0.light.ErrorUtil;

public class FileUtil {


	/**
	 * returns '.pdf' for 'bla.2.pdf'
	 * 
	 */
		public static String getFileExtension(String path) {
			int sepIdx=path.lastIndexOf('.');
			if (sepIdx==-1)
				return "";
			String retVal= path.substring(sepIdx);
			return retVal;
		}
		
		
		/**
		 * read a stream until the end, and return the contents read as a stream
		 */
		
		public static String readStream(InputStream raw){
			try{
				StringBuilder builder=new StringBuilder();
				BufferedReader in=new BufferedReader(new InputStreamReader(raw));
				String line;
				while((line=in.readLine())!=null){
					if (builder.length()>0)
						builder.append("\n");
					builder.append(line);
				}
				return builder.toString();
				}
			catch (IOException e){
				throw ErrorUtil.propagateError(e);
			}
		}
		

	    /**
	     * handling of named exception is usually ... plain wrong
	     * @param stream
	     */
	    public static void closeStream(InputStream stream){
	    	try {
	    	 stream.close();
	    	} catch (Exception e){
	    		throw ErrorUtil.propagateError(e);
	    	}    			
	    }
	    

	    public static Properties loadPropertiesStream(InputStream in, boolean andClose){
	    	try {
				Properties properties = new Properties();
			    
				Reader reader=new InputStreamReader(in,"UTF-8");
			    properties.load(reader);    
			    
			    if (andClose)
			    	in.close();
			    return properties;
			} catch (Exception e) {
				throw ErrorUtil.propagateError(e);
			}
		
		}
	    

	    
	    public static Properties loadPropertiesFile(String path){
	    	try {
			
			    FileInputStream fis;
				fis = new FileInputStream(path);
				Properties properties =loadPropertiesStream(fis,true);
			    return properties;
			} catch (Exception e) {
				throw ErrorUtil.propagateError(e);
			}
		
		}


        public static void bytes2file(String fileName, byte[] bytes) {
            
            try{
                FileOutputStream out=new FileOutputStream(fileName);
                out.write(bytes);
                out.close();
            } catch (Exception e){
                throw  ErrorUtil.propagateError(e);
            }
            
        }


        public static InputStream bytes2Stream(byte[] data) {
        	return new ByteArrayInputStream(data);
        }


        public static byte[] file2bytes(String fileName) {
            try {
                InputStream inputStream=new FileInputStream(new File(fileName).getAbsolutePath());
                byte[] retVal=stream2Bytes(inputStream,true);
                
                return retVal;
            } catch (IOException e) {
            	throw ErrorUtil.propagateError("for file: "+fileName,e);
            }
            
        }


        public static void file2file(String source,String dest){
        	try{
        		FileInputStream inputStream=new FileInputStream(source);
        		FileOutputStream outputStream=new FileOutputStream(dest);
        		stream2stream(inputStream, outputStream);
        		inputStream.close();
        		outputStream.close();
        	} catch (Exception e){
        		throw ErrorUtil.propagateError(e);
        	}
        }


        public static List<String> file2lines(String fileName) {
            return Arrays.asList(file2string(fileName).split("\n"));
        }


        public static String file2string(String fileName) {
            try {
                InputStream inputStream=new FileInputStream(fileName);
                String retVal=stream2String(inputStream,true);
                return retVal;
            } catch (IOException e) {
            	throw ErrorUtil.propagateError("for file: "+fileName,e);
            }
            
        }


        public static String resource2string(ClassLoader classLoader,String resourceName) {
        	 InputStream inputStream;
        	 if (classLoader!=null)
        		 inputStream=classLoader.getResourceAsStream(resourceName);
        	 else
        		 inputStream=FileUtil.class.getResourceAsStream(resourceName);
        	
             try {
             	return stream2String(inputStream,true);
             }
             catch (Exception e){
             	throw ErrorUtil.propagateError("for resource: "+resourceName,e);
             }
        }


        public static String resource2string(String resourceName) {
            return resource2string(null,resourceName);
        
            
        }


        // http://threebit.net/mail-archive/itext-questions/msg02387.html
        // much nicer than mine
        private static byte[] stream2Bytes(InputStream stream,boolean andClose) {
            try {
                if (stream == null) {
                    return null;
                } else {
                    ByteArrayOutputStream byteArray = new ByteArrayOutputStream();
                    byte buffer[] = new byte[1024];
                    int c = 0;
                    while ((c = stream.read(buffer)) > 0) {
                        byteArray.write(buffer, 0, c);
                    }
                    byteArray.flush();
                    return byteArray.toByteArray();
                }
            } catch (IOException e) {
               
                throw ErrorUtil.propagateError(e);
            } finally {
            	 if (stream != null)  FileUtil.closeStream(stream);
            }
        }


        public static List<String> stream2list(InputStream resourceAsStream,boolean andClose) {
            try {
                BufferedReader reader=new BufferedReader(new InputStreamReader(resourceAsStream));
                List<String> retVal=new ArrayList<String>();
                String line;
                while((line=reader.readLine())!=null)
                    retVal.add(line);
                return retVal;
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                FileUtil.closeStream(resourceAsStream);
            }
            
        }


        public static int stream2stream(InputStream inputStream,
        		OutputStream outputStream) {
        	try{
        		int retVal=0;
        		byte[]data=new byte[1024];
        		while(true){
        			int read=inputStream.read(data);
        			if (read==0)
        				Thread.sleep(100); // blocking IO would be better
        			else if (read==-1)
        				break;
        			else {
        				outputStream.write(data,0,read);
        			}
        			retVal+=read;
        		}
        		return retVal;
        	
        	} catch (Exception e) {
        		throw ErrorUtil.propagateError(e);
        	}
        	
        }


        public static String stream2String(InputStream inputStream,boolean andClose) {
            return new String(stream2Bytes(inputStream,andClose));
        }


        /**
         * if fileName is - then stdout is used
         * @param fileName
         * @param data
         */
        public static void string2file(String fileName, String data) {
            string2file(fileName, data,false);
        }


        public static void string2file(String fileName, String data,boolean append) {
            try{
                if (fileName.equals("-"))
                    System.out.print(data);
                else {
                    FileOutputStream out=new FileOutputStream(fileName,append);
                    out.write(data.getBytes());
                    out.close();
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            
            
        }


        public static InputStream string2stream(byte[] data) {
        	return new ByteArrayInputStream(data);
        }
	    
}
